home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
5
/
GRAF3D
/
GRAF3D_D.OC
< prev
next >
Wrap
Text File
|
1992-07-19
|
12KB
|
383 lines
Graf3D: The Three-dimensional Graphics Library
Graf3D draws three dimensional graphics in the two-dimensional environment
provided by Quickdraw.
Graf3D presents a "camera-eye view" of the objects drawn. With Graf3D
procedures, the programmer sets the camera's location and field-of-view,
as well as the location and orientation of the object being viewed. Graf3D
manages a "viewing pyramid" whose apex is at the camera's eye and whose base is
Graf3D's "ViewPort". The Graf3D package will clip objects being viewed to this
pyramid.
The Graf3D package makes extensive use of the "fixed point" data type. "Fixed"
is defined as:
type
fixed = longint;
The high order word of a fixed variable is the integer part; the low order
word is the fraction part. Values are represented in units of 1/65536ths. For
example, the number 2.5 would be represented by a "2" in the high word and a
32768 in the low order word (32768/65536 = .5), which would yield the longint
value 163840. Another way to think of it is that the value of a "fixed"
variable is the value of the longint divided by 65536. For more detail see
Inside Macintosh in the "Introduction to Memory Management" chapter.
Graf3D Types
Point3D
A Point3D is a record containing three "fixed" coordinates.
Point3D = record
x : fixed;
y : fixed;
z : fixed;
end;
Point2D
A Point2D is a record containing two "fixed" coordinates.
Point2D = record
x : fixed;
y : fixed;
end;
XfMatrix
An XfMatrix is a 4x4 matrix of "fixed" values that holds the transformation
equation for points to be viewed.
XfMatrix = array [0..3, 0..3] of fixed;
Port3D
The Port3D contains all of the state variables necessary to map the three
dimensional coordinates of the image into the two dimensional screen coordinates.
"GrPort" is the pointer to the QuickDraw grafPort associated with this Port3D.
"viewRect" is the viewing rectangle within the Port3D. "xLeft, yTop, xRight,
yBottom" are the coordinates of the viewRect in the three-dimensional "world".
"pen" is the three dimensional pen location. "penPrime" is the pen location
transformed by the "xForm" matrix. "eye" is the position of the camera in
three-dimensional coordinates. "hSize, vSize" are the half-width and half-
height of the viewPort in screen coordinates. "hCenter, vCenter" are the
coordinates of the center of the viewPort in screen coordinates. "xCotan,
yCotan" are the cotangents of the horizontal and vertical viewing angles.
"ident" is a boolean which is true when "xForm" is equal to the identity
transformation. "xForm" is the transformation matrix.
Port3DPtr = ^Port3D;
Port3D = record
GrPort : GrafPtr;
viewRect : Rect;
xLeft, yTop, xRight, yBottom : fixed;
pen, penPrime, eye : Point3D;
hSize, vSize : fixed;
hCenter, vCenter : fixed;
xCotan, yCotan : fixed;
ident : BOOLEAN;
xForm : XfMatrix;
end;
Graf3D Procedures and Functions
Graf3D is a three dimensional Quickdraw package. Its types, variable and
routines mimic Quickdraw in many ways. The following procedures and functions
are provided in the Graf3D package:
Graf3DPort port initialization routines:
var thePort3D : Port3DPtr;
procedure InitGrf3D (globalPtr : Ptr);
InitGrf3D initializes the Graf3D drawing environment. This procedure should be
called once and only once per program execution, after Quickdraw is initialized.
"globalPtr" is a pointer to the storage you wish to use for the Graf3D global
variables. Lightspeed Pascal programmers should always pass "@thePort3D" in
this parameter.
procedure Open3DPort (port : Port3DPtr);
Open3DPort opens and initializes a 3D GrafPort whose space is pointed to by the
parameter "port". It also sets "thePort3D" (the current Graf3DPort) to "port".
procedure SetPort3D (port : Port3DPtr);
SetPort3D sets the current Graf3DPort ("thePort3D") to "port" and calls SetPort
for "port"'s associated grafPort.
procedure GetPort3D (var port : Port3DPtr);
GetPort3D returns a pointer to the current graf3DPort in "port". This is useful
when the programmer wishes to change ports for drawing something and then
restore the port before proceeding with the rest of the program. For example:
var
myPort, savePort: Port3DPtr;
...
GetPort3D( savePort ); { save the current port }
SetPort3D( myPort ); { set the port to my own }
{ I can do my drawing now╔ }
SetPort3D( savePort ); { restore the port to the one saved }
Pen movement and drawing
The following routines are used to move the pen in the 3D space and draw lines
in the space. NOTE: The coordinates in these routines are specified in "fixed
point" notation (NOT INTEGERS as in Quickdraw).
procedure MoveTo2D (x, y : fixed);
procedure MoveTo3D (x, y, z : fixed);
These procedures move the pen to the designated coordinates. (MoveTo2D moves
without changing the Z-coordinate.)
procedure LineTo2D (x, y : fixed);
procedure LineTo3D (x, y, z : fixed);
These procedures draw lines from the current pen position to the given
coordinates (LineTo2D draws without changing the z-coordinate, i.e. the line is
drawn in the same z-plane.)
procedure Move2D (dx, dy : fixed);
procedure Move3D (dx, dy, dz : fixed);
These procedures move the pen by the specified amounts relative to the current
pen position. (Move2D moves without changing the Z-coordinate.)
procedure Line2D (dx, dy : fixed);
procedure Line3D (dx, dy, dz : fixed);
These procedures draw lines from the current pen position to the given offsets
relative to the current pen position (Line2D draws without changing the
z-coordinate, i.e. the line is drawn in the same z-plane.)
function Clip3D (src1, src2 : Point3D; var dst1, dst2 : POINT): boolean;
Clip3D clips a three-dimensional line segment to the viewing pyramid and returns
the clipped line projected onto screen coordinates. Clip3D returns true if any
part of the line is visible.
procedure SetPt3D ( var pt3D : Point3D; x, y, z : fixed);
SetPt3D assigns the 3 fixed numbers "x,y,z" to the point pt3D.
procedure SetPt2D ( var pt2D : Point2D; x, y : fixed);
SetPt3D assigns the 2 fixed numbers "x,y" to the point pt2D.
Setting up the point of view
The following three procedures set the position and field-of-view of the "point
of view".
procedure LookAt (left, top, right, bottom : fixed);
LookAt specifies the real number x,y coordinates of the viewing rectangle.
procedure ViewPort (r : Rect);
ViewPort specifies where to put the image in the grafPort. The ViewPort
rectangle is specified in integer coordinates and tells where to map the LookAt
coordinates.
procedure ViewAngle (angle : fixed);
ViewAngle controls the amount of perspective by specifying the horizontal angle
subtended by the viewing rectangle. Typical ViewAngles are 0í (no perspective),
10í (telephoto lens), 25í (normal human eye), and 80í (wide angle lens).
Transformation matrix procedures
The following procedures modify the transformation matrix that is used to plot
the points in the viewing coordinates.
procedure Identity;
Identity sets the transformation matrix to the identity matrix.
procedure Scale (xFactor, yFactor, zFactor : fixed);
Scale modifies the transformation matrix so as to shrink or expand the image by
the factors specified.
procedure Translate (dx, dy, dz : fixed);
Transform modifies the transformation matrix so as to displace the image by the
specified amounts in the three coordinates.
procedure Pitch (xAngle : fixed);
Pitch modifies the transformation matrix so as to rotate "xangle" degrees around
the x axis. Positive values cause a clockwise rotation when looking at the
origin from positive x.
procedure Yaw (yAngle : fixed);
Yaw modifies the transformation matrix so as to rotate "yAngle" degrees around
the y axis. Positive values cause a clockwise rotation when looking at the
origin from positive y.
procedure Roll (zAngle : fixed);
Roll modifies the transformation matrix so as to rotate "zAngle" degrees around
the z axis. Positive values cause a clockwise rotation when looking at the
origin from positive z.
procedure Skew (zAngle : fixed);
Skew modifies the transformation matrix so as to skew the image by "zAngle"
degrees around the z axis. Skew only changes the x axis. Positive values cause
a clockwise rotation when looking at the origin from positive z.
procedure TransForm (src : Point3D; var dst : Point3D);
Transform applies the transformation matrix to the "src" point, and returns the
result in "dst".
program boxes;
uses
Graf3D;
const
boxcount = 10;
type
box3d = record
pt1 : Point3D;
pt2 : point3D;
dist : real;
end;
var
GPort1 : GrafPort;
GPort2 : Port3D;
myPort : GrafPtr;
myPort3D : Port3DPtr;
boxArray : array[0..boxCount] of Box3D;
nBoxes : integer;
i : integer;
ph : picHandle;
r : rect;
function HeapError (hz : QDPtr;
bytesNeeded : integer) : integer;
begin
writeln('The heap is full!!!');
end;
function Distance (pt1, pt2 : Point3D) : real;
var
dx, dy, dz : real;
begin
dx := pt2.x - pt1.x;
dy := pt2.y - pt1.y;
dz := pt2.z - pt1.z;
Distance := sqrt(dx * dx + dy * dy + dz * dz);
end;
procedure MakeBox;
label
99;
var
myBox : Box3D;
i, j, k, v : integer;
p1, p2 : point3D;
myRect : Rect;
testRect : Rect;
begin
p1.x := (Random mod 140 - 85) * 65536;
p1.y := (Random mod 140 - 80) * 65536;
p1.z := 0;
p2.x := p1.x + (10 + abs(Random) mod 30) * 65536;
p2.y := p1.y + (10 + abs(Random) mod 45) * 65536;
p2.z := p1.z + (10 + abs(Random) mod 35) * 65536;
SetRect(myRect, round(p1.x div 65536), round(p1.y div 65536), round(p2.x div 65536), round(p2.y div 65536));
for i := 1 to nBoxes - 1 do
begin
with boxArray[i] do
SetRect(testRect, round(pt1.x DIV 65536), round(pt1.y DIV 65536), round(pt2.x DIV 65536), round(pt2.y DIV 65536));
if sectrect(myRect, testRect, testRect) then
goto 99;
end;
myBox.pt1 := p1;
myBox.pt2 := p2;
p1.x := (p1.x + p2.x) DIV 2;
p1.y := (p1.y + p2.y) DIV 2;
p1.z := (p1.z + p2.z) DIV 2;
Transform(p1, p2);
myBox.dist := Distance(p2, myPort3D^.eye);
i := 0;
boxArray[nBoxes].dist := myBox.dist;
while myBox.dist > boxArray[i].dist do
i := i + 1;
for j := nBoxes downto i + 1 do
boxArray[j] := boxArray[j - 1];
boxArray[i] := myBox;
nBoxes := nBoxes + 1;
99 :
end;
procedure drawBox (pt1, pt2 : Point3D);
var
tempRgn : RgnHandle;
begin
tempRgn := NewRgn;
OpenRgn;
MoveTo3D(pt1.x, pt1.y, pt1.z);
LineTo3D(pt1.x, pt1.y, pt2.z);
LineTo3D(pt2.x, pt1.y, pt2.z);
LineTo3D(pt2.x, pt1.y, pt1.z);
LineTo3D(pt1.x, pt1.y, pt1.z);
CloseRgn(tempRgn);
FillRgn(tempRgn, white);
FrameRgn(tempRgn);
OpenRgn;
MoveTo3D(pt1.x, pt1.y, pt2.z);
LineTo3D(pt1.x, pt2.y, pt2.z);
LineTo3D(pt2.x, pt2.y, pt2.z);
LineTo3D(pt2.x, pt1.y, pt2.z);
LineTo3D(pt1.x, pt1.y, pt2.z);
CloseRgn(tempRgn);
FillRgn(tempRgn, gray);
OpenRgn;
MoveTo3D(pt2.x, pt1.y, pt1.z);
LineTo3D(pt2.x, pt1.y, pt2.z);
LineTo3D(pt2.x, pt2.y, pt2.z);
LineTo3D(pt2.x, pt2.y, pt1.z);
LineTo3D(pt2.x, pt1.y, pt1.z);
CloseRgn(tempRgn);
FillRgn(tempRgn, black);
PenPat(white);
MoveTo3D(pt2.x, pt2.y, pt2.z);
LineTo3D(pt2.x, pt2.y, pt1.z);
LineTo3D(pt2.x, pt1.y, pt1.z);
PenNormal;
DisposeRgn(tempRgn);
end;
begin
setrect(r, 0, 40, 512, 342);
SetDrawingRect(r);
InitGrf3D(@thePort3D);
showdrawing;
GetPort(myPort);
ph := OpenPicture(myPort^.portRect);
showpen;
myPort3D := @GPort2;
Open3DPort(myPort3D);
ViewPort(myPort^.portRect);
LookAt($FF9C0000, $4B0000, $640000, $FFB50000);
ViewAngle($200000);
Identity;
Roll($140000);
Pitch($460000);
PenPat(white);
BackPat(black);
EraseRect(myPort^.portRect);
for i := -10 to 10 do
begin
MoveTo3D(i * 10 * 65536, -100 * 65536, 0);
LineTo3D(i * 10 * 65536, 100 * 65536, 0);
end;
for i := -10 to 10 do
begin
MoveTo3D(-100 * 65536, i * 10 * 65536, 0);
LineTo3D(100 * 65536, i * 10 * 65536, 0);
end;
nBoxes := 0;
repeat
MakeBox
until nBoxes = boxCount;
for i := nBoxes - 1 downto 0 do
DrawBox(boxArray[i].pt1, boxArray[i].pt2);
HidePen;
ClosePicture;
readln
end.